\subsection{Когда много \IT{case} в одном блоке}

Вот очень часто используемая конструкция: несколько \IT{case} может быть использовано в одном блоке:

\lstinputlisting[style=customc]{patterns/08_switch/3_several_cases/several_cases.c}

Слишком расточительно генерировать каждый блок для каждого случая, поэтому обычно
генерируется каждый блок плюс некий диспетчер.

\subsubsection{MSVC}

\lstinputlisting[caption=\Optimizing MSVC 2010,numbers=left,style=customasmx86]{patterns/08_switch/3_several_cases/several_cases_MSVC_2010_Ox_RU.asm}

Здесь видим две таблицы: первая таблица (\TT{\$LN10@f}) это таблица индексов,
а вторая таблица (\TT{\$LN11@f}) это массив указателей на блоки.

В начале, входное значение используется как индекс в таблице индексов (строка 13). 

Вот краткое описание значений в таблице: 
0 это первый блок \IT{case} (для значений 1, 2, 7, 10),
1 это второй (для значений 3, 4, 5),
2 это третий (для значений 8, 9, 21),
3 это четвертый (для значений 22),
4 это для блока по умолчанию.

Мы получаем индекс для второй таблицы указателей на блоки и переходим туда (строка 14).

Ещё нужно отметить то, что здесь нет случая для нулевого входного значения.

Поэтому мы видим инструкцию \DEC на строке 10 и таблица начинается с $a=1$.
Потому что незачем выделять в таблице элемент для $a=0$.

Это очень часто используемый шаблон.

В чем же экономия?
Почему нельзя сделать так, как уже обсуждалось (\myref{switch_lot_GCC}), используя только одну таблицу, содержащую указатели на блоки?
Причина в том, что элементы в таблице индексов занимают только по 8-битному байту, поэтому всё это более компактно.

\subsubsection{GCC}

GCC делает так, как уже обсуждалось (\myref{switch_lot_GCC}), используя просто таблицу указателей.

\subsubsection{ARM64: \Optimizing GCC 4.9.1}

Во-первых, здесь нет кода, срабатывающего в случае если входное значение~--- 0, так что GCC пытается
сделать таблицу переходов более компактной и начинает со случая, когда входное значение~--- 1.

GCC 4.9.1 для ARM64 использует даже более интересный трюк.
Он может закодировать все смещения как 8-битные байты.
Вспомним, что все инструкции в ARM64 имеют размер в 4 байта.

GCC также использует тот факт, что все смещения в моем крохотном примере находятся достаточно близко друг от друга.

Так что таблица переходов состоит из байт.

\lstinputlisting[caption=\Optimizing GCC 4.9.1 ARM64,style=customasmARM]{patterns/08_switch/3_several_cases/ARM64_GCC491_O3_RU.s}

Скомпилируем этот пример как объектный файл и откроем его в \IDA. Вот таблица переходов:

\lstinputlisting[caption=jumptable in IDA,style=customasmARM]{patterns/08_switch/3_several_cases/ARM64_GCC491_O3_IDA.lst}

В случае 1, 9 будет умножено на 9 и прибавлено к адресу метки \TT{Lrtx4}.

В случае 22, 0 будет умножено на 4, в результате это 0.

Место сразу за меткой \TT{Lrtx4} это метка L7, где находится код, выводящий \q{22}.

В сегменте кода нет таблицы переходов, место для нее выделено в отдельной секции .rodata
(нет особой нужды располагать её в сегменте кода).

Там есть также отрицательные байты (0xF7). Они используются для перехода назад, на код, выводящий
строку \q{default} (на \TT{.L2}).

